package com.atom.common.dao;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.apache.log4j.Logger;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.transform.Transformers;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.HibernateTemplate;

import com.atom.common.util.JsonUtil;

/**
 * Title: AvensCommonDao
 * Description: 抽象DAO，提供一些最基本的数据库操作，采用泛型方式
 *
 * @author WEWE
 * @version 1.0
 * @date 2015-11-12 上午12:28:01
 */
public abstract class AvensCommonDao<T extends Serializable> {

	Logger logger = Logger.getLogger(AvensCommonDao.class);

	@Resource
	protected HibernateTemplate hibernateTemplate;

	private Class<T> entityClass;

	@SuppressWarnings("unchecked")
	public AvensCommonDao() {
		this.entityClass = null;
		Class<?> c = getClass();
		Type t = c.getGenericSuperclass();
		if (t instanceof ParameterizedType) {
			Type[] p = ((ParameterizedType) t).getActualTypeArguments();
			this.entityClass = (Class<T>) p[0];
		}
	}

	/**
	 * Description: 删除一个对象，无返回值
	 *
	 * @param instance
	 * @return
	 */
	public void delete(T instance) {
		if (instance != null) {
			logger.info("=====Delete Begin=====");
			logger.info("INSTANCE : " + JsonUtil.ObjectToJsonQuietly(instance));
			hibernateTemplate.delete(instance);
		}
	}

	/**
	 * Description: 更新某几个字段
	 * @param hql
	 */
	public int update(String hql){
		logger.info("=====Update Begin=====");
		logger.info("HQL : " + hql);
		return hibernateTemplate.bulkUpdate(hql);
	}

	/**
	 * Description: 删除多个对象
	 *
	 * @param instances
	 * @return
	 */
	public void deleteAll(List<T> instances) {
		if (instances != null && instances.size() > 0) {
			logger.info("=====Delete Begin=====");
			for (T instance : instances)
				logger.info("INSTANCE : " + instance.toString());
			hibernateTemplate.deleteAll(instances);
		}
	}

	/**
	 * Description: 根据HQL语句查找
	 *
	 * @param query
	 * @return List<T>
	 */
	@SuppressWarnings("rawtypes")
	public List executeQuery(String query) {
		logger.info("=====Execute Query Begin=====");
		logger.info("HQL : " + query);
		return hibernateTemplate.find(query);
	}

	@SuppressWarnings("rawtypes")
	public List executeQuery(String query, Object value) {
		logger.info("=====Execute Query Begin=====");
		logger.info("HQL : " + query);
		return hibernateTemplate.find(query, value);
	}

	@SuppressWarnings("rawtypes")
	public List executeQuery(String query, Object[] values) {
		logger.info("=====Execute Query Begin=====");
		logger.info("HQL : " + query);
		return hibernateTemplate.find(query, values);
	}

	/**
	 * Description: 分页查询
	 *
	 * @param query
	 * @param pageIndex
	 * @param pageSize
	 * @return List<T>
	 */
	@SuppressWarnings("unchecked")
	public List<Object> executeQueryByPage(final String query, final int pageIndex,
			final int pageSize) {
		logger.info("=====Query By Page Begin=====");
		logger.info("HQL : " + query);
		logger.info("pageIndex : " + pageIndex);
		logger.info("pageSize : " + pageSize);
		return (List<Object>) hibernateTemplate.execute(
				new HibernateCallback<Object>() {
					public Object doInHibernate(Session session)
							throws HibernateException, SQLException {
						Query createQuery = session.createQuery(query);
						if (pageIndex != 0) {
							createQuery.setFirstResult((pageIndex - 1)
									* pageSize);
						}
						createQuery.setMaxResults(pageSize);
						return createQuery.list();
					}
				});
	}

	@SuppressWarnings("rawtypes")
	public List executeSql(String sql, Class<?> theClass) {
		Session session;
		try {
			session = hibernateTemplate.getSessionFactory()
					.getCurrentSession();
		} catch (Exception e) {
			session =  hibernateTemplate.getSessionFactory().openSession();
		}
		SQLQuery query = session.createSQLQuery(sql);
		query.setResultTransformer(Transformers.aliasToBean(theClass));
		List list = query.list();
		return list;
	}
	@Deprecated
	public void saveAll(List<T> list){
		if (list.size() != 0) {
			final int DIVISOR = 500;//每存储500个对象提交一次事务
			final int quotient = list.size()/DIVISOR;
			final int remainder = list.size()%DIVISOR;
			final Iterator<T> it = list.iterator();

			hibernateTemplate.execute(new HibernateCallback<Void>() {
				public Void doInHibernate(Session session)
						throws HibernateException, SQLException {

					Transaction transaction;

					for(int i=1; i <= quotient; i++){
						transaction = session.beginTransaction();
						System.out.println("transaction:" + transaction);
						for(int p=1; p <= DIVISOR; p++){
							session.save(it.next());
						}
						transaction.commit();
						session.clear();
					}

					transaction = session.beginTransaction();
					for(int i = 1; i <= remainder; i++){
						session.save(it.next());
					}
					transaction.commit();
					session.close();
					return null;
				}
			});
		}

	}

	/**
	 * Description: 带分页的根据HQL语句查找
	 * 返回结果为新的Bean类型的List
	 * 适用于联查和部分查询
	 *
	 * @param query
	 * @param clazz
	 * @return
	 */
	@SuppressWarnings({"rawtypes"})
	public List executeQueryGetBeanResultByPage(final String query, final Class<?> clazz,
			final Integer pageIndex, final Integer pageSize) {
		logger.info("=====Query Get Bean Result By Page Begin=====");
		logger.info("HQL : " + query);
		logger.info("clazz : " + clazz.getName());
		logger.info("pageIndex : " + pageIndex);
		logger.info("pageSize : " + pageSize);
		return (List) hibernateTemplate.execute(
				new HibernateCallback<Object>() {
					public Object doInHibernate(Session session)
							throws HibernateException, SQLException {
						Query createQuery = session.createQuery(query)
								.setResultTransformer(Transformers.aliasToBean(clazz));
						if (null != pageIndex && pageIndex != 0) {
							createQuery.setFirstResult((pageIndex - 1)
									* pageSize);
							createQuery.setMaxResults(pageSize);
						}
						return createQuery.list();
					}
				});
	}

	/**
	 * Description: 执行SQL语句
	 *
	 * @param query
	 * @return
	 */
	public void executeSQLQuery(String query) {
		SQLQuery createSQLQuery = hibernateTemplate
				.getSessionFactory().openSession().createSQLQuery(query);
		createSQLQuery.executeUpdate();
	}

	/**
	 * Description: 根据主键查找
	 *
	 * @param id
	 * @return T
	 */
	public T findById(Object id) {
		logger.info("=====Query By Id Begin=====");
		logger.info("Id : " + id);
		return hibernateTemplate.get(entityClass, (Serializable) id);
	}

	/**
	 * Description: <p>根据多个条件查找，
	 * 传入参数为属性名与属性值构成的hashmap，
	 * key为属性名，value为属性值</p>
	 *
	 * @param properties
	 * @return List<T>
	 */
	@SuppressWarnings("unchecked")
	public List<T> findByProperties(Map<String, Object> properties) {
		logger.info("=====Query By Properties Begin=====");
		logger.info("properties : " + JsonUtil.ObjectToJsonQuietly(properties));
		StringBuffer sql = new StringBuffer("from " + entityClass.getName() + " as model where 1=1");
		List<Object> values = new ArrayList<Object>();
		for (String key : properties.keySet()) {
			if (properties.get(key) != null) {
				sql.append(" and model." + key + " = ?");
				values.add(properties.get(key));
			}
		}

		return (List<T>) hibernateTemplate.find(sql.toString(), values.toArray());
	}

	/**
	 * Description: 根据单个条件查找，property为属性名，value为属性值
	 *
	 * @param property
	 * @param value
	 * @return List<T>
	 */
	@SuppressWarnings("unchecked")
	public List<T> findByProperty(String property, Object value) {
		logger.info("=====Query By Property Begin=====");
		logger.info("property : " + property);
		logger.info("value : " + value);
		String sql = "from " + entityClass.getName() + " as model where model."
				+ property + "=?";
		return (List<T>) hibernateTemplate.find(sql, value);
	}

	public Class<T> getEntityClass() {
		return entityClass;
	}
	
	@SuppressWarnings("unchecked")
    public List<T> findByPropertyOrderBy(String property, Object value, String column) {
        logger.info("=====Query By Property Begin=====");
        logger.info("property : " + property);
        logger.info("value : " + value);
        String sql = "from " + entityClass.getName() + " as model where model."
                + property + "=? order by " + column;
        return (List<T>) hibernateTemplate.find(sql, value);
    }


	/**
	 * Description: 根据单个条件模糊查找，property为属性名，value为属性值
	 *
	 * @param property
	 * @param value
	 * @return List<T>
	 */
	@SuppressWarnings("unchecked")
	public List<T> findByLikeProperty(String property, Object value) {
		logger.info("=====Query By Like Property Begin=====");
		logger.info("property : " + property);
		logger.info("value : " + value);
		String sql = "from " + entityClass.getName() + " as model where model."
				+ property + " like % ? %";
		return (List<T>) hibernateTemplate.find(sql, value);
	}

	/**
	 * Description: 查询全表条目数量
	 *
	 * @param
	 * @return Integer
	 */
	public Integer getSize() {
		final String hql = "select count(*) from "
				+ entityClass.getSimpleName();
		Integer result = null;
		result = Integer.valueOf(hibernateTemplate.execute(
				new HibernateCallback<Object>() {
					public Object doInHibernate(Session session)
							throws HibernateException, SQLException {
						Query query = session.createQuery(hql);
						return query.uniqueResult();
					}
				}).toString());
		return result;
	}

	public Integer getSize(final String sqlQuery) {
		logger.info("=====Get Size Begin=====");
		logger.info("sqlQuery : " + sqlQuery);
		Integer result = null;
		result = Integer.valueOf(hibernateTemplate.execute(
				new HibernateCallback<Object>() {
					public Object doInHibernate(Session session)
							throws HibernateException, SQLException {
						Query query = session.createQuery(sqlQuery);
						return query.uniqueResult();
					}
				}).toString());
		return result;
	}

	/**
	 * Description: 插入或更新一个对象，返回该对象
	 *
	 * @param instance
	 * @return T
	 */
	public T merge(T instance) {
		logger.info("=====Merge Begin=====");
		logger.info("INSTANCE : " + JsonUtil.ObjectToJsonQuietly(instance));
		return hibernateTemplate.merge(instance);
	}

	/**
	 * Description: 插入一个新对象
	 *
	 * @param instance
	 * @return
	 */
	public Object save(T instance) {
		logger.info("=====Save Begin=====");
		logger.info("INSTANCE : " + JsonUtil.ObjectToJsonQuietly(instance));
		return hibernateTemplate.save(instance);
	}

	/**
	 * Description: 插入或更新一个对象，无返回值
	 *
	 * @param instance
	 * @return
	 */
	public void saveOrUpdate(T instance) {
		logger.info("=====SaveOrUpdate Begin=====");
		logger.info("INSTANCE : " + JsonUtil.ObjectToJsonQuietly(instance));
		hibernateTemplate.saveOrUpdate(instance);
	}

	/**
	 * Description: 分页查询全部数据
	 *
	 * @param pageIndex
	 * @param pageSize
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public List<T> selectAllByPage(final int pageIndex, final int pageSize) {
		final String query = "from " + entityClass.getName();
		return (List<T>) hibernateTemplate.execute(
				new HibernateCallback<Object>() {
					public Object doInHibernate(Session session)
							throws HibernateException, SQLException {
						Query createQuery = session.createQuery(query);
						if (pageIndex != 0) {
							createQuery.setFirstResult((pageIndex - 1)
									* pageSize);
						}
						createQuery.setMaxResults(pageSize);
						return createQuery.list();
					}
				});
	}

	@SuppressWarnings("unchecked")
	public List<T> getAll() {
		StringBuffer query = new StringBuffer("from " + entityClass.getName());
		return executeQuery(query.toString());
	}

	public void setEntityClass(Class<T> entityClass) {
		this.entityClass = entityClass;
	}

	/**
	 * Description: 更新对象，无返回值
	 *
	 * @param instance
	 * @return
	 */
	public void update(T instance) {
		logger.info("=====Update Begin=====");
		logger.info("INSTANCE : " + JsonUtil.ObjectToJsonQuietly(instance));
		hibernateTemplate.update(instance);
	}
	
	@SuppressWarnings("unchecked")
	  public List<T> findByPropertysAndPageAndOrder(String property,String property2,
			  final String value,final String value2,final int start,final int count,
			  final String orderstr,final String descstr) {
		    logger.info("=====Query By Property Begin=====");
		    logger.info("property : " + property);
		    logger.info("property : " + property2);
		    logger.info("value : " + value);
		    final String sql = "from " + entityClass.getName() + " as model where model."
		        + property + "=? and model."
		        + property2 + " like ? order by "+orderstr+" "+descstr;
		    return (List<T>) hibernateTemplate.execute(
		            new HibernateCallback<Object>() {
		              public Object doInHibernate(Session session)
		                  throws HibernateException, SQLException {
		                Query createQuery = session.createQuery(sql);
		                createQuery.setString(0, value);
		                createQuery.setString(1, "%"+value2+"%");
		                createQuery.setFirstResult(start);
		                createQuery.setMaxResults(count);
		                return createQuery.list();
		              }
		            });
		  }
	
	@SuppressWarnings("unchecked")
	  public List<T> findByPropertysAndPageAndOrder(
			  String property,String property2,String property3,
			  final String value,final String value2,final String value3,
			  final int start,final int count,
			  final String orderstr,final String descstr) {
		    logger.info("=====Query By Property Begin=====");
		    logger.info("property : " + property);
		    logger.info("property : " + property2);
		    logger.info("value : " + value);
		    final String sql = "from " + entityClass.getName() + " as model where model."
		        + property + "=? and model."
		        + property2 + " like ? and model."
		        + property3 + " = ? order by "+orderstr+" "+descstr;
		    return (List<T>) hibernateTemplate.execute(
		            new HibernateCallback<Object>() {
		              public Object doInHibernate(Session session)
		                  throws HibernateException, SQLException {
		                Query createQuery = session.createQuery(sql);
		                createQuery.setString(0, value);
		                createQuery.setString(1, "%"+value2+"%");
		                createQuery.setString(2, value3);
		                createQuery.setFirstResult(start);
		                createQuery.setMaxResults(count);
		                return createQuery.list();
		              }
		            });
		  }

	@SuppressWarnings("unchecked")
	  public List<T> findByPropertys(String property,String property2, 
			  String value, String value2) {
	    logger.info("=====Query By Property Begin=====");
	    logger.info("property : " + property);
	    logger.info("value : " + value);
	    logger.info("property : " + property2);
	    logger.info("value : " + value2);
	    String sql = "from " + entityClass.getName() + " as model where model."
	        + property + "=? and model."
	        + property2 + " like ?";
	    return (List<T>) hibernateTemplate.find(sql, value,"%"+value2+"%");
	  }

	  /**
	   * Description: 根据单个条件查找，property为属性名，value为属性值
	   *
	   * @param property
	   * @param value
	   * @return List<T>
	   */
	  @SuppressWarnings("unchecked")
	  public List<T> findByPropertys(String property,String property2,String property3, 
			  String value, String value2, String value3) {
	    logger.info("=====Query By Property Begin=====");
	    logger.info("property : " + property);
	    logger.info("value : " + value);
	    logger.info("property : " + property2);
	    logger.info("value : " + value2);
	    String sql = "from " + entityClass.getName() + " as model where model."
	        + property + "=? and model."
	        + property2 + " like ?"
	        + "and model."
	        + property3 + " =?";
	    return (List<T>) hibernateTemplate.find(sql, value,"%"+value2+"%", value3);
	  }
	  @SuppressWarnings("unchecked")
	  public List<T> findByPropertyAndPageAndOrder(String property, final String value, 
			  final int start, final int count, final String orderstr,final String descstr) {
	    logger.info("=====Query By Property Begin=====");
	    logger.info("property : " + property);
	    logger.info("value : " + value);
	    final String sql = "from " + entityClass.getName() + " as model where model."
	        + property + "=? order by "+orderstr+" "+descstr;
	    return (List<T>) hibernateTemplate.execute(
	            new HibernateCallback<Object>() {
	              public Object doInHibernate(Session session)
	                  throws HibernateException, SQLException {
	                Query createQuery = session.createQuery(sql);
	                createQuery.setString(0, value);
	                createQuery.setFirstResult(start);
	                createQuery.setMaxResults(count);
	                return createQuery.list();
	              }
	            });
	  }
	  
	  @SuppressWarnings("unchecked")
	  public List<T> findByMapAndPageAndOrder(Map<String,String> map, 
			  final int start, final int count,
			  final String orderstr,final String descstr) {
	    logger.info("=====Query By Property Begin=====");
	    logger.info("map : " + map);
	     String sql = "from " + entityClass.getName() + " as model where 1=1 ";
	    int i = map.keySet().size();
	    String val[] = new String[i];
	    int j = 0;
	    for(String key :map.keySet()){
	    	String value = map.get(key);
	    	sql += " and model."+key+"=? ";
	    	val[j] = value;
	    	j++;
	    }
	    sql += " order by "+orderstr+" "+descstr;
	    final String executesql = sql;
	    return (List<T>) hibernateTemplate.execute(
	            new HibernateCallback<Object>() {
	              public Object doInHibernate(Session session)
	                  throws HibernateException, SQLException {
	                Query createQuery = session.createQuery(executesql);
	                for(int k = 0;k<val.length;k++){
	                	createQuery.setString(k, val[k]);
	                }
	                
	                createQuery.setFirstResult(start);
	                createQuery.setMaxResults(count);
	                return createQuery.list();
	              }
	            });
	  }
	  
	  @SuppressWarnings({"unchecked", "rawtypes"})
	  public void executeSQL(final String sql) {
	    hibernateTemplate.execute(new HibernateCallback() {
	      public Object doInHibernate(Session session) throws HibernateException,
	      SQLException {
	        session.createSQLQuery(sql).executeUpdate();
	        return null;
	      }
	    });
	  }
}